const templateRe = /\{ *([\w_ -]+) *\}/g;
const tileSize = 256;
// @function template(str: String, data: Object): String
// Simple templating facility, accepts a template string of the form `'Hello {a}, {b}'`
// and a data object like `{a: 'foo', b: 'bar'}`, returns evaluated string
// `('Hello foo, bar')`. You can also specify functions instead of strings for
// data values — they will be evaluated passing `data` as an argument.
export const template = (str, data) => {
  return str.replace(templateRe, (str, key) => {
    let value = data[key];

    if (value === undefined) {
      throw new Error(`未为变量提供值 ${str}`);
    } else if (typeof value === "function") {
      value = value(data);
    }
    return value;
  });
};

export const extend = (dest, ...args) => {
  let j, len, src;

  for (j = 0, len = args.length; j < len; j++) {
    src = args[j];
    // eslint-disable-next-line guard-for-in
    for (const i in src) {
      dest[i] = src[i];
    }
  }

  return dest;
};

/**
 * 经纬度转为瓦片坐标
 * @param {*} longitude  经度 (值大的那个)
 * @param {*} latitude  纬度
 * @param {*} zoom 层级
 * @returns
 */
export const LatLongToTileXY = (longitude, latitude, zoom) => {
  // 地球的周长的一半 20037508.342789244 单位米
  const circumferenceHalf = Math.PI * 6378137;

  const mx = (longitude * circumferenceHalf) / 180;

  const temp =
    Math.log(Math.tan((90 + latitude) * (Math.PI / 360.0))) / (Math.PI / 180.0);
  const my = (circumferenceHalf * temp) / 180;
  // 米/每像素
  const resolution = (Math.PI * 2 * 6378137) / (tileSize * Math.pow(2, zoom));

  // px = (mx + circumferenceHalf) / resolution
  const px = ((longitude + 180) / 360) * Math.pow(2, zoom) * tileSize;
  // py = (my + circumferenceHalf) / resolution
  const py =
    ((circumferenceHalf * temp) / 180 + circumferenceHalf) /
    (Math.PI * 2 * 6378137) /
    (tileSize * Math.pow(2, zoom));

  // tx = Math.floor(px / tileSize)
  const tx = Math.floor(((longitude + 180) / 360) * Math.pow(2, zoom));
  // ty = (1 - arsinh(tan(latitude * π / 180)) / π) * Math.pow(2, zoom)
  // 双曲正弦函数 arsinh(x) => ln(x + (x^2 + 1)^0.5)
  const ty = Math.floor(
    ((1 -
      Math.log(
        Math.tan((latitude * Math.PI) / 180) +
          1 / Math.cos((latitude * Math.PI) / 180)
      ) /
        Math.PI) /
      2) *
      Math.pow(2, zoom)
  );

  return { tx, ty };
};

/**
 * 瓦片转为经纬度,左上角
 * @param {*} tx
 * @param {*} ty
 * @param {*} zoom
 * @returns
 */
export const TileXYToLatLong = (tx, ty, zoom) => {
  const longitude = (tx / Math.pow(2, zoom)) * 360 - 180;

  const tmp = Math.PI - (2 * Math.PI * ty) / Math.pow(2, zoom);

  // latitude = (180 / Math.PI) * Math.atan(sinh(tmp))
  // 双曲函数sinh(x)=(e^x - e^(-x)) * 0.5
  const latitude =
    (180 / Math.PI) * Math.atan(0.5 * (Math.exp(tmp) - Math.exp(-tmp)));

  return { longitude, latitude };
};


/**
 * 经纬度转米
 * @param {*} longitude 
 * @param {*} latitude 
 * @returns 
 */
export const LatLongToMeterXY = (longitude, latitude) => {
  // 地球的周长的一半 20037508.342789244 单位米
  const circumferenceHalf = (Math.PI * 2 * 6378137) / 2.0;
  const mx = (longitude * circumferenceHalf) / 180;
  const temp =
    Math.log(Math.tan((90 + latitude) * (Math.PI / 360.0))) / (Math.PI / 180.0);
  const my = (circumferenceHalf * temp) / 180;

  return { mx, my };
};


/**
 * 米转像素
 * @param {*} mx 
 * @param {*} my 
 * @param {*} zoom 
 * @returns 
 */
export const MetersToPixelXY = (mx, my, zoom) => {
  // 地球的周长的一半 20037508.342789244 单位米
  const circumferenceHalf = (Math.PI * 2 * 6378137) / 2.0;

  // 米/每像素
  const resolution = (Math.PI * 2 * 6378137) / (tileSize * Math.pow(2, zoom));

  const px = (mx + circumferenceHalf) / resolution;
  const py = (my + circumferenceHalf) / resolution;

  return { px, py };
};



/**
 * 像素坐标转瓦片坐标;
 * @param {*} px 
 * @param {*} py 
 * @returns 
 */
export const PixelXYToTileXY = (px, py) => {
  const tx = Math.floor(px / tileSize);
  const ty = Math.floor(py / tileSize);
  
  return { tx, ty }
}